package com.example.cloud_disk.service.impl;


import cn.mybatis.mp.core.mybatis.mapper.context.Pager;
import cn.mybatis.mp.core.sql.executor.chain.DeleteChain;
import cn.mybatis.mp.core.sql.executor.chain.QueryChain;
import cn.mybatis.mp.core.sql.executor.chain.UpdateChain;
import com.example.cloud_disk.FileReading.CsvService;
import com.example.cloud_disk.FileReading.ExcelService;
import com.example.cloud_disk.constant.FileTypeConstant;
import com.example.cloud_disk.constant.PasswordConstant;
import com.example.cloud_disk.constant.StatusConstant;
import com.example.cloud_disk.dto.*;
import com.example.cloud_disk.entity.AdminUsers;
import com.example.cloud_disk.entity.Files;
import com.example.cloud_disk.entity.Users;
import com.example.cloud_disk.hdfsApi.HdfsOperationsService;
import com.example.cloud_disk.mapper.AdminUsersMapper;
import com.example.cloud_disk.mapper.FilesMapper;
import com.example.cloud_disk.mapper.UsersMapper;
import com.example.cloud_disk.service.UsersService;
import com.example.cloud_disk.utils.JwtUtil;
import com.example.cloud_disk.utils.Md5Util;
import com.example.cloud_disk.utils.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URISyntaxException;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author majun
 * @package com.example.cloud_disk.service.impl
 * @date 2024/10/22 22:01
 */

@Service
@Slf4j
public class UsersServiceImpl implements UsersService {

    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private AdminUsersMapper adminUsersMapper;

    @Autowired
    private FilesMapper filesMapper;

    @Autowired
    private HdfsOperationsService hdfsOperationsService;

    @Autowired
    private ExcelService excelService;

    @Autowired
    private CsvService csvService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    /**
     * 创建单个用户
     *
     * @param userDTO
     */
    @Transactional
    public String saveUser(UserDTO userDTO) throws URISyntaxException, IOException, InterruptedException {

        //获取当前管理员用户id和username
        Map<String, Object> map = ThreadLocalUtil.get();

        AdminUsers adminUsers = adminUsersMapper.get(where -> {
            where.eq(AdminUsers::getId, map.get("id"));
        });

        //查看管理员是否有权限
        if (adminUsers.getCanDeleteUser().equals(StatusConstant.ENABLE)) {

            Users users = new Users();

            BeanUtils.copyProperties(userDTO, users);

            users.setCreatedAt(new Date());
            users.setPassword(Md5Util.getMD5String(PasswordConstant.DEFAULT_PASSWORD));
            users.setStatus(StatusConstant.ENABLE);

            String path = "/users/" + userDTO.getStudentNumber();

            hdfsOperationsService.createDirectory(path);

            usersMapper.save(users);

            return "用户创建成功";

        }

        return "用户没有权限";

    }

    /**
     * 通过用户上传的Excel或csv文件批量注册用户
     *
     * @param file
     * @param fileType
     * @return
     */
    @Transactional
    public String saveUsers(MultipartFile file, String fileType) {
        Map<String, Object> map = ThreadLocalUtil.get();

        AdminUsers adminUsers = adminUsersMapper.get(where -> {
            where.eq(AdminUsers::getId, map.get("id"));
        });

        if (adminUsers.getCanDeleteUser().equals(StatusConstant.DISABLE)) {
            return "账户权限不足";
        }

        if (fileType.equals(FileTypeConstant.Excel)) {

            // Excel处理逻辑
            Map<String, String> usersMap = excelService.readExcel(file);

            int numberOfThreads = Runtime.getRuntime().availableProcessors();
            ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);

            // 初始化CompletableFuture数组
            CompletableFuture<?>[] futures = new CompletableFuture[usersMap.size()];
            int i = 0;

            // 使用传统的for循环遍历用户数据
            for (Map.Entry<String, String> entry : usersMap.entrySet()) {
                CompletableFuture future = CompletableFuture.runAsync(() -> {
                    try {
                        save(entry.getKey(), entry.getValue()); // 调用save方法保存用户
                    } catch (Exception e) {
                        e.printStackTrace(); // 打印异常信息
                    }
                }, executorService);
                futures[i++] = future;
            }

            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException ex) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }

            // 等待所有CompletableFuture完成
            CompletableFuture.allOf(futures).join();

            return "用户保存成功";

        }

        if (fileType.equals(FileTypeConstant.CSV)) {

            // CSV处理逻辑
            Map<String, String> usersMap = csvService.readCsv(file);

            int numberOfThreads = Runtime.getRuntime().availableProcessors();
            ExecutorService executorService = Executors.newFixedThreadPool(numberOfThreads);

            // 初始化CompletableFuture数组
            CompletableFuture<?>[] futures = new CompletableFuture[usersMap.size()];
            int i = 0;

            // 使用传统的for循环遍历用户数据
            for (Map.Entry<String, String> entry : usersMap.entrySet()) {
                CompletableFuture future = CompletableFuture.runAsync(() -> {
                    try {
                        save(entry.getKey(), entry.getValue()); // 调用saveUser方法保存用户
                    } catch (Exception e) {
                        e.printStackTrace(); // 打印异常信息
                    }
                }, executorService);
                futures[i++] = future;
            }

            executorService.shutdown();
            try {
                if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
                    executorService.shutdownNow();
                }
            } catch (InterruptedException ex) {
                executorService.shutdownNow();
                Thread.currentThread().interrupt();
            }

            // 等待所有CompletableFuture完成
            CompletableFuture.allOf(futures).join();

            return "用户保存成功";

        }

        return "用户创建失败";

    }

    /**
     * 修改用户账号状态
     *
     * @param id
     * @return
     */
    public String upDataUserStatus(Integer id) {

        Map<String, Object> map = ThreadLocalUtil.get();

        Integer AdminId = (Integer) map.get("id");

        AdminUsers adminUsers = QueryChain.of(adminUsersMapper)
                .eq(AdminUsers::getId, AdminId)
                .get();

        if (adminUsers.getCanDisableUser().equals(StatusConstant.DISABLE)) {

            return "账户权限不足";

        }

        Users users = usersMapper.get(where -> {

            where.eq(Users::getId, id);

        });

        // 切换用户状态
        Integer newStatus = users.getStatus() == StatusConstant.ENABLE ? StatusConstant.DISABLE : StatusConstant.ENABLE;

        users.setStatus(newStatus);

        usersMapper.update(users);

        return "用户账户状态修改成功";

    }

    /**
     * 用户登录
     *
     * @param userLoginDTO
     * @return
     */
    public String login(UserLoginDTO userLoginDTO) {

        Users users = usersMapper.get(where -> {
            where.eq(Users::getStudentNumber, userLoginDTO.getStudentNumber());
        });

        if (users == null) {

            return "账号不存在";

        }

        if (users.getStatus() == StatusConstant.DISABLE) {

            return "账户已被禁用";

        }

        if (users.getPassword().equals(Md5Util.getMD5String(userLoginDTO.getPassword()))) {

            //账户密码正确，返回token
            HashMap<String, Object> claims = new HashMap<>();
            claims.put("id", users.getId());
            claims.put("studentNumber", users.getStudentNumber());
            String token = JwtUtil.genToken(claims);

            //将token存如redis
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(token, token, 12, TimeUnit.HOURS);

            users.setLastLogin(new Date());

            usersMapper.update(users);

            return token;

        }

        return "密码错误";

    }

    /**
     * 文件上传
     *
     * @param file
     * @return
     */
    @Transactional
    public String upFiles(MultipartFile file) throws InterruptedException, IOException, URISyntaxException {

        Map<String, Object> map = ThreadLocalUtil.get();

        String fileName = file.getOriginalFilename();

        double fileSizeInMB = file.getSize() / (1024.0);
        String fileSize = new DecimalFormat("#.00").format(fileSizeInMB) + "KB";

        String filePath = "/users/" + map.get("studentNumber") + "/" + fileName;

        Files files = new Files();

        files.setFileName(fileName);
        files.setFilePath(filePath);
        files.setFileSize(fileSize);
        files.setCreatedId((Integer) map.get("id"));
        files.setCreatedAt(new Date());

        filesMapper.save(files);

        hdfsOperationsService.uploadingFiles(file, filePath);

        return "文件上传成功";

    }

    /**
     * 用户文件分页及模糊查询
     *
     * @return
     */
    public Pager<Files> getPageUsersFile(GetFilesPageDTO getFilesPageDTO) {

        Map<String, Object> map = ThreadLocalUtil.get();

        String userId = map.get("id").toString();

        Pager<Files> pager = QueryChain.of(filesMapper)
                // 忽略 null 条件参数
                .ignoreNullValueInCondition(true)
                // 忽略 空字符串 条件参数
                .ignoreEmptyInCondition(true)
                .like(Files::getCreatedId, userId)
                .like(Files::getFileName, getFilesPageDTO.getFileName())
                .paging(Pager.of(getFilesPageDTO.getPageNumber(), getFilesPageDTO.getPageSize()));

        return pager;

    }

    /**
     * 用户账号分页及模糊查询
     *
     * @param getUsersPageDTO
     * @return
     */
    public Pager<Users> getAllUsersPage(GetUsersPageDTO getUsersPageDTO) {

        return QueryChain.of(usersMapper)
                .ignoreNullValueInCondition(true)
                .ignoreEmptyInCondition(true)
                .like(Users::getUsername, getUsersPageDTO.getUsername())
                .paging(Pager.of(getUsersPageDTO.getPageNumber(), getUsersPageDTO.getPageSize()));

    }

    /**
     * 用户修改基本信息
     *
     * @param upDataUser
     * @param token
     * @return
     */
    @Transactional
    public String upDataUser(UpDataUser upDataUser, String token) {

        Map<String, Object> map = ThreadLocalUtil.get();

        if (upDataUser.getUsername().isEmpty() || upDataUser.getEmail().isEmpty()) {

            return "姓名，邮箱不能为空";

        }

        if (upDataUser.getPassword().isEmpty()) {

            Users users = usersMapper.get(where -> {
                where.eq(Users::getId, map.get("id"));
            });

            upDataUser.setPassword(users.getPassword());

        } else {

            upDataUser.setPassword(Md5Util.getMD5String(upDataUser.getPassword()));

            stringRedisTemplate.delete(token);

        }

        upDataUser.setId((Integer) map.get("id"));

        usersMapper.update(upDataUser);

        return "用户信息修改成功";

    }

    /**
     * 用户文件下载
     *
     * @param id
     * @return
     */
    public String fileDown(String id) throws URISyntaxException, IOException {

        Map<String, Object> map = ThreadLocalUtil.get();

        Files files = filesMapper.get(where -> {
            where.eq(Files::getId, id);
        });

        if (files.getCreatedId().equals(map.get("id"))) {

            return hdfsOperationsService.fileDownload(files.getFilePath(), files.getFileName());

        } else {

            return "非本人文件禁止下载";

        }


    }

    /**
     * 用户文件删除
     *
     * @param id
     * @return
     */
    @Transactional
    public String fileDel(String id) throws IOException, InterruptedException {

        Map<String, Object> map = ThreadLocalUtil.get();

        Files files = filesMapper.get(where -> {
            where.eq(Files::getId, id);
        });

        if (files.getCreatedId().equals(map.get("id"))) {

            hdfsOperationsService.fileDelete(files.getFilePath());

            filesMapper.delete(where -> {
                where.eq(Files::getId, id);
            });

            return "文件删除成功";

        } else {

            return "非本人文件禁止操作";

        }

    }

    /**
     * 用户账户删除
     *
     * @param id
     * @return
     */
    public String deleteUser(Integer id) throws IOException, InterruptedException {

        Map<String, Object> map = ThreadLocalUtil.get();

        AdminUsers adminUsers = adminUsersMapper.get(where -> {
            where.eq(AdminUsers::getId, map.get("id"));
        });

        Users users = usersMapper.get(where -> {
            where.eq(Users::getId, id);
        });

        if (adminUsers.getCanDeleteUser().equals(StatusConstant.DISABLE)) {

            return "账户权限不足";
        }

        String filePath = "/users/" + users.getStudentNumber();

//        hdfsOperationsService.deleteFolder(filePath);

        usersMapper.delete(where -> {
            where.eq(Users::getId, id);
        });

        return "用户删除成功";

    }

    /**
     * 用户修改密码
     *
     * @param putPassword
     * @param token
     * @return
     */
    public String putUserPassword(PutPassword putPassword, String token) {

        Map<String, Object> map = ThreadLocalUtil.get();

        Users users = usersMapper.get(where -> {
            where.eq(Users::getId, map.get("id"));
        });

        if (!users.getPassword().equals(Md5Util.getMD5String(putPassword.getOldPassword()))) {

            return "密码不正确，请联系管理员";

        }

        if (!putPassword.getNewPassword().equals(putPassword.getConfirmPassword())) {
            return "用户两次输入密码不一致";
        }

        users.setPassword(Md5Util.getMD5String(putPassword.getNewPassword()));

        stringRedisTemplate.delete(token);

        usersMapper.update(users);

        return "用户密码修改成功";
    }


    /**
     * 用户创建
     *
     * @param username
     * @param studentNumber
     * @throws URISyntaxException
     * @throws IOException
     * @throws InterruptedException
     */
    public void save(String username, String studentNumber) throws URISyntaxException, IOException, InterruptedException {
        Users users = new Users();
        users.setUsername(username);
        users.setStudentNumber(studentNumber);
        users.setStatus(StatusConstant.ENABLE);
        users.setCreatedAt(new Date());
        users.setPassword(Md5Util.getMD5String(PasswordConstant.DEFAULT_PASSWORD));

        String path = "/users/" + studentNumber;
        hdfsOperationsService.createDirectory(path);

        usersMapper.save(users);
    }

}
